package com.example.test3ddemo

// 导入必要的类

import android.animation.ValueAnimator
import android.content.Context
import android.os.Bundle
import android.util.Log
import android.view.GestureDetector
import android.view.MotionEvent
import android.view.ScaleGestureDetector
import android.view.animation.AccelerateDecelerateInterpolator
import android.widget.Button
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.FileProvider
import androidx.core.view.doOnLayout
import com.google.android.filament.Material
import io.github.sceneview.SceneView
import io.github.sceneview.loaders.ModelLoader
import io.github.sceneview.math.Position
import io.github.sceneview.math.Rotation
import io.github.sceneview.math.Scale
import io.github.sceneview.model.ModelInstance
import io.github.sceneview.node.ModelNode
import io.github.sceneview.node.Node
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.io.File
import java.io.IOException
import java.nio.ByteBuffer
import kotlin.math.abs
import com.google.android.filament.MaterialInstance as FilamentMaterialInstance
import io.github.sceneview.model.Model as FilamentModel


/**
 * 主活动类，负责3D模型的展示和材质控制
 */
class MainActivity : AppCompatActivity() {
    private lateinit var sceneView: SceneView
    // 添加一个标志来跟踪 SceneView 是否已经初始化
    private var isSceneViewInitialized = false
    // 存储节点原始材质的字典，key为节点名称，value为材质对象
    private val originalMaterials = mutableMapOf<String, FilamentMaterialInstance>()
    // 记录当前模型的旋转角度（以弧度为单位）
    private var currentRotation = 0f
    // 添加一个变量来保存模型节点的引用
    private var currentModelNode: ModelNode? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        // 初始化 SceneView
        sceneView = findViewById(R.id.sceneView)

        setupScene()

        // 创建UI
        setupUI()



    }

    /**
     * 设置3D场景
     * 包括加载模型、设置光照等
     */
    private fun setupScene() {
        try {
            // 在协程中加载模型
            CoroutineScope(Dispatchers.Main).launch {
                try {
//                    val fileName = "models/RunPluss.gltf"
//                    val inputStream = assets.open(fileName) // 🔥 用 InputStream
//                    val tempFile = File.createTempFile("temp_model", ".gltf", cacheDir)
//                    tempFile.outputStream().use { output ->
//                        inputStream.copyTo(output)
//                    }
//                    val uri = FileProvider.getUriForFile(applicationContext, "${packageName}.fileprovider", tempFile)
//                    Log.d("TAG", "📌 加载模型路径: $uri")


                    val glbData =
                        loadGLBFromAssets(this@MainActivity, "models/Terra_3D_demo.gltf") ?: return@launch
                    val modelInstance = sceneView.modelLoader.createModelInstance(glbData) // 🔥 使用 Uri
                    // 在主线程处理 UI 相关操作
                    if (modelInstance != null) {
                        val modelNode = ModelNode(modelInstance).apply {
                            position = Position(x = 0.0f, y = 0.0f, z = -5.0f)
                            scale = Scale(1.0f)
                            rotation = Rotation(x = 0.0f, y = 0.0f, z = 0.0f)
                        }
                        // 保存模型节点的引用
                        currentModelNode = modelNode
                        // 获取模型实例
                        val model = modelNode.model
                        if (model != null) {
//                             保存原始材质
                            saveOriginalMaterials(model)
                            // 应用特定材质
                            val glassMaterial = createGlassMaterial()

                            applySpecificMaterials(model,glassMaterial)
                        }
                        Log.d("MainActivity", "🎨 该节点的材质: $modelNode")
                        // 添加到场景
                        sceneView.addChildNode(modelNode) // 将模型添加到 SceneView
                        modelNode.modelInstance?.materialInstances?.forEach {
                            Log.d("MainActivity", "🎨 该节点的材质: ${it.name}")
                        }
                        getAllNodes(modelNode)


                        Toast.makeText(this@MainActivity, "模型加载成功", Toast.LENGTH_SHORT).show()
                    } else {
                        Toast.makeText(this@MainActivity, "模型加载失败：返回为空", Toast.LENGTH_LONG).show()
                    }

                } catch (e: Exception) {
                    Log.e("MainActivity", "Error loading model${e.localizedMessage}", e)
                    Toast.makeText(
                        this@MainActivity,
                        "模型加载失败: ${e.localizedMessage}",
                        Toast.LENGTH_LONG
                    ).show()
                }

            }

        } catch (e: Exception) {
            Log.e("MainActivity", "Error in setupScene", e)
            Toast.makeText(this, "场景设置失败: ${e.localizedMessage}", Toast.LENGTH_LONG).show()
        }

        // 设置场景光照
//        setupLighting()
    }


    fun getAllNodes(rootNode: Node): List<Node> {
        val nodeList = mutableListOf<Node>()
        nodeList.add(rootNode)
        Log.d("MainActivity", "节点名称: ${rootNode.name}")
        sceneView.childNodes.forEach { node ->
//            getAllNodes(node)
        }
//        getAllNodes(rootNode.childNodes.forEach())
//        for (i in 0 until rootNode.childNodes.size) {
//            nodeList.addAll()
//        }
        return nodeList
    }

    /**
     * 设置场景光照
     * 添加环境光和定向光源
     */
    private fun setupLighting() {
        sceneView.environment?.apply {
            // 设置间接光照
            indirectLight?.apply {
                intensity = 1.0f
            }
        }
    }

    /**
     * 创建玻璃材质
     * 设置透明、光滑、高反射的玻璃效果
     * @return 配置好的玻璃材质
     */
    private fun createGlassMaterial(): FilamentMaterialInstance {
        val inputStream = this.assets.open("materials/terra_bl.filamat")
        val byteArray = inputStream.readBytes()
        inputStream.close()
        val buffer = ByteBuffer.wrap(byteArray)

        val material = Material.Builder()
            .payload(buffer,byteArray.size)
            .build(sceneView.engine)
        
        return material.createInstance().apply {
            setParameter("baseColor", 1.0f, 0.0f, 0.0f) // 纯红色
            setParameter("metallic", 0.0f)
            setParameter("roughness", 0.0f)
//            setParameter("opacity", 0.7f)
        }
    }

    /**
     * 创建金属材质
     * 设置高金属度、适中粗糙度的金属效果
     * @return 配置好的金属材质
     */
    private fun createMetalMaterial(): FilamentMaterialInstance {
        val inputStream = this.assets.open("materials/terra_bl.filamat")
        val byteArray = inputStream.readBytes()
        inputStream.close()
        val buffer = ByteBuffer.wrap(byteArray)

        val material = Material.Builder()
            .payload(buffer,byteArray.size)
            .build(sceneView.engine)
        
        return material.createInstance().apply {
            setParameter("baseColor", 1.0f, 0.0f, 0.0f) // 纯红色
            setParameter("metallic", 0.0f)
            setParameter("roughness", 0.0f)
        }
    }

    /**
     * 创建硅胶材质
     * 设置柔和、半透明的硅胶效果
     * @return 配置好的硅胶材质
     */
    private fun createSiliconeMaterial(filePath : String): FilamentMaterialInstance {
        val inputStream = this.assets.open("materials/terra_bl.filamat")
        val byteArray = inputStream.readBytes()
        inputStream.close()
        val buffer = ByteBuffer.wrap(byteArray)
        val material = Material.Builder()
            .payload(buffer,byteArray.size)
            .build(sceneView.engine)
        
        return material.createInstance().apply {
            setParameter("baseColor", 1.0f, 0.0f, 0.0f) // 纯红色
            setParameter("metallic", 0.0f)
            setParameter("roughness", 0.0f)
//            setParameter("opacity", 0.8f)
        }
    }

    /**
     * 创建塑料材质
     * 设置适中反射和粗糙度的塑料效果
     * @return 配置好的塑料材质
     */
    private fun createPlasticMaterial(): FilamentMaterialInstance {

        val inputStream = this.assets.open("materials/terra_bl.filamat")
        val byteArray = inputStream.readBytes()
        inputStream.close()
        val buffer = ByteBuffer.wrap(byteArray)

        val material = Material.Builder()
            .payload(buffer,byteArray.size)
            .build(sceneView.engine)
        
        return material.createInstance().apply {
            setParameter("baseColor", 1.0f, 0.0f, 0.0f) // 纯红色
            setParameter("metallic", 0.0f)
            setParameter("roughness", 0.0f)
        }
    }

    /**
     * 创建发光材质
     * 设置自发光效果
     * @return 配置好的发光材质
     */
    private fun createGlowMaterial(): FilamentMaterialInstance {
        val inputStream = this.assets.open("materials/terra_bl.filamat")
        val byteArray = inputStream.readBytes()
        inputStream.close()
        val buffer = ByteBuffer.wrap(byteArray)


        val material = Material.Builder()
            .payload(buffer,byteArray.size)
            .build(sceneView.engine)
        
        return material.createInstance().apply {
            setParameter("baseColor", 1.0f, 0.0f, 0.0f) // 纯红色
            setParameter("metallic", 0.0f)
            setParameter("roughness", 0.0f)
        }
    }

    /**
     * 保存原始材质
     */
    private fun saveOriginalMaterials(model: FilamentModel) {
        model.instance?.let { instance ->

            instance.materialInstances.forEachIndexed { index, material ->
                val name = material.name
                if (name != null) {
                    originalMaterials[name] = material
                }
            }
        }
    }

    /**
     * 应用特定材质到指定节点
     */
    private fun applySpecificMaterials(model: FilamentModel,newMaterial: FilamentMaterialInstance) {
        if (currentModelNode == null) return

        // 定义节点和对应材质的映射关系
        val specificMaterials = mapOf(
            "brep_9_1_" to createGlassMaterial(),
            "brep_21" to createSiliconeMaterial("materials/terra_bl.filamat"),
            "brep_1_1_" to createPlasticMaterial(),
            "brep_6_1_" to createMetalMaterial(),
            "brep_2_1_" to createGlowMaterial()
        )


        model.instance?.let { modelInstance->
            if (modelInstance.materialInstances.isEmpty()) {
                Log.e("MainActivity", "❌ 该 ModelInstance 没有材质可替换")
                return
            }
            modelInstance.materialInstances.forEachIndexed { index, _ ->
                modelInstance.materialInstances[index] = newMaterial
                sceneView.invalidate()

                Log.d("MainActivity", "✅ 成功应用新材质到索引 $index")
                Log.d("MainActivity", "✅ modelInstance.materialInstances ：：${modelInstance.materialInstances[index].name}.")
                Log.d("MainActivity", "✅ newMaterial 加载成功  ：${newMaterial.name}")
            }
            newMaterial.material.parameters.forEach { param ->
                Log.d("MainActivity", "🎨 材质支持的参数: ${param.name}")
            }
            // 🚀 确保 UI 刷新
            sceneView.invalidate()
            currentModelNode!!.modelInstance?.materialInstances?.forEach {
                Log.e("MainActivity", "🎨 该节点的材质: ${it.name}")
            }
            Log.d("MainActivity", "🎨 材质更换成功！")
        }

        // 遍历应用材质
        model.instance?.let { instance ->
            specificMaterials.forEach { (nodeName, material) ->
                try {
                    instance.materialInstances.forEachIndexed { index, existingMaterial ->
                        if (existingMaterial.name == nodeName) {
                            instance.materialInstances[index] = material
                            Log.d("MainActivity", "Applied material to node: $nodeName")
                        }
                    }
                } catch (e: Exception) {
                    Log.e("MainActivity", "Failed to apply material to node: $nodeName", e)
                }
            }
        }
    }

    /**
     * 设置UI和事件处理
     * 初始化按钮点击事件和手势控制
     */
    private fun setupUI() {
        // 原始材质按钮：恢复所有节点的原始材质
        findViewById<Button>(R.id.btnOriginal).setOnClickListener {
            restoreOriginalMaterials()
        }

        // 玻璃材质按钮：将所有节点设置为玻璃材质
        findViewById<Button>(R.id.btnGlass).setOnClickListener {
            applyMaterialToAllNodes(createGlassMaterial())
        }

        // 硅胶材质按钮：将所有节点设置为硅胶材质
        findViewById<Button>(R.id.btnSilicone).setOnClickListener {
            applyMaterialToAllNodes(createSiliconeMaterial("materials/terra_bl.filamat"))
        }

        // 金属材质按钮：将所有节点设置为金属材质
        findViewById<Button>(R.id.btnMetal).setOnClickListener {
            applyMaterialToAllNodes(createMetalMaterial())
        }

        // 设置手势控制
        setupGestureControl()
    }

    /**
     * 应用材质到所有节点
     */
    private fun applyMaterialToAllNodes(newMaterial: FilamentMaterialInstance) {
        currentModelNode?.model?.let { model ->
            model.instance?.let { instance ->
                // 创建从0到1的动画器
                val animator = ValueAnimator.ofFloat(0f, 1f)
                animator.duration = 500
                animator.interpolator = AccelerateDecelerateInterpolator()

                // 保存当前所有材质的副本
                val currentMaterials = mutableMapOf<Int, FilamentMaterialInstance>()
                instance.materialInstances.forEachIndexed { index, material ->
                    currentMaterials[index] = material

                }

                // 动画更新监听器
                animator.addUpdateListener { animation ->
                    val fraction = animation.animatedValue as Float
                    currentMaterials.forEach { (index, currentMaterial) ->
                        try {
                            val transitionMaterial = createTransitionMaterial(
                                currentMaterial,
                                newMaterial,
                                fraction
                            )
                            instance.materialInstances[index] = transitionMaterial
                        } catch (e: Exception) {
                            Log.e("MainActivity", "Error applying transition material", e)
                        }
                    }
                }

                // 动画结束监听器
                animator.addListener(object : android.animation.Animator.AnimatorListener {
                    override fun onAnimationStart(animation: android.animation.Animator) {}
                    override fun onAnimationEnd(animation: android.animation.Animator) {
                        instance.materialInstances.forEachIndexed { index, _ ->
                            instance.materialInstances[index] = newMaterial
                        }
                    }
                    override fun onAnimationCancel(animation: android.animation.Animator) {}
                    override fun onAnimationRepeat(animation: android.animation.Animator) {}
                })

                // 开始动画
                animator.start()
            }
        }
    }

    private fun createTransitionMaterial(
        start: FilamentMaterialInstance,
        end: FilamentMaterialInstance,
        fraction: Float
    ): FilamentMaterialInstance {
        val inputStream = this.assets.open("materials/terra_bl.filamat")
        val byteArray = inputStream.readBytes()
        inputStream.close()
        val buffer = ByteBuffer.wrap(byteArray)
        val material = Material.Builder()
            .payload(buffer,byteArray.size)
            .build(sceneView.engine)

        return material.createInstance().apply {
            // 使用默认值进行过渡
            setParameter("baseColor", 
                lerp(0.53f, 0.75f, fraction),
                lerp(0.8f, 0.75f, fraction),
                lerp(1.0f, 0.75f, fraction)
            )

            setParameter("metallic", lerp(0.0f, 0.0f, fraction))
            setParameter("roughness", lerp(0.0f, 0.0f, fraction))

            try {
//                setParameter("opacity", lerp(0.7f, 1.0f, fraction))
            } catch (e: Exception) {
                // 忽略没有透明度参数的材质
            }

//            try {
////                setParameter("emissive",
////                    lerp(0.0f, 0.0f, fraction),
////                    lerp(0.0f, 0.0f, fraction),
////                    lerp(0.0f, 0.0f, fraction)
//                )
//                setParameter("emissiveStrength", lerp(0.0f, 0.0f, fraction))
//            } catch (e: Exception) {
//                // 忽略没有自发光参数的材质
//            }

            try {
                setParameter("clearCoat", lerp(0.0f, 0.0f, fraction))
                setParameter("clearCoatRoughness", lerp(0.0f, 0.0f, fraction))
            } catch (e: Exception) {
                // 忽略没有清漆涂层参数的材质
            }
        }
    }

    private fun lerp(start: Float, end: Float, fraction: Float): Float {
        return start + (end - start) * fraction
    }

    /**
     * 恢复所有节点的原始材质
     */
    private fun restoreOriginalMaterials() {
        currentModelNode?.model?.let { model ->
            model.instance?.let { instance ->
                originalMaterials.forEach { (name, material) ->
                    instance.materialInstances.forEachIndexed { index, existingMaterial ->
                        if (existingMaterial.name == name) {
                            instance.materialInstances[index] = material
                        }
                    }
                }
            }
        }
    }

    /**
     * 设置手势控制
     */
    private fun setupGestureControl() {
        val scaleGestureDetector = ScaleGestureDetector(this, object : ScaleGestureDetector.SimpleOnScaleGestureListener() {
            private var lastScaleFactor = 1.0f

            override fun onScale(detector: ScaleGestureDetector): Boolean {
                currentModelNode?.let { modelNode ->
                    val scaleFactor = detector.scaleFactor
                    // 限制缩放范围
                    val newScale = lastScaleFactor * scaleFactor
                    if (newScale in 0.1f..5.0f) {
                        lastScaleFactor = newScale
                        modelNode.scale = Scale(newScale)  // 使用单一值创建统一缩放
                    }
                }
                return true
            }

            override fun onScaleBegin(detector: ScaleGestureDetector): Boolean {
                currentModelNode?.let { modelNode ->
                    lastScaleFactor = modelNode.scale.x  // 使用当前x缩放值作为基准
                }
                return true
            }
        })

        val gestureDetector = GestureDetector(this, object : GestureDetector.SimpleOnGestureListener() {
            override fun onScroll(
                e1: MotionEvent?,
                e2: MotionEvent,
                distanceX: Float,
                distanceY: Float
            ): Boolean {
                // 只处理水平滑动，忽略较大的垂直滑动
                if (abs(distanceY) >= 3) return false

                // 根据滑动距离旋转模型
                currentModelNode?.let { modelNode ->
                    val rotationDelta = -distanceX * 0.5f  // 将滑动距离转换为旋转角度
                    currentRotation += rotationDelta
                    modelNode.rotation = Rotation(0f, currentRotation, 0f)
                }
                return true
            }
        })

        sceneView.setOnTouchListener { _, event ->
            scaleGestureDetector.onTouchEvent(event)
            gestureDetector.onTouchEvent(event)
            true
        }
    }

    override fun onResume() {
        super.onResume()
        if (isSceneViewInitialized) {
            try {
                // 恢复渲染
//                sceneView.renderMode = SceneView.RenderMode.RENDER_CONTINUOUSLY
            } catch (e: Exception) {
                Log.e("MainActivity", "Error resuming SceneView", e)
            }
        }
    }

    override fun onPause() {
        super.onPause()
        if (isSceneViewInitialized) {
            try {
                // 暂停渲染以节省资源
//                sceneView.renderMode = SceneView.RenderMode.RENDER_WHEN_DIRTY
            } catch (e: Exception) {
                Log.e("MainActivity", "Error pausing SceneView", e)
            }
        }
    }

    override fun onDestroy() {
        try {
            // 清理材质资源
            originalMaterials.clear()
            // 只有在 SceneView 已初始化的情况下才调用 destroy
            if (isSceneViewInitialized) {
                try {
                    sceneView.destroy()
                } catch (e: Exception) {
                    Log.e("MainActivity", "Error destroying SceneView", e)
                }
            }
        } catch (e: Exception) {
            Log.e("MainActivity", "Error in onDestroy", e)
        } finally {
            super.onDestroy()
        }
    }

    fun loadGLBFromAssets(context: Context, filePath: String): ByteBuffer? {
        return try {
            Log.i("MainActivity====", "loadGLBFromAssets: $filePath")
            val inputStream = context.assets.open(filePath)
            val bytes = inputStream.readBytes()
            inputStream.close()
            ByteBuffer.wrap(bytes)
        } catch (e: IOException) {
            e.printStackTrace()
            null
        }
    }


}